테스트 실습 - 계산기 테스트
✒️ 2025-07-24 18:08 내용 수정
계산기 클래스
- Spring 프로젝트에서
StringCalculator클래스를 생성한다. - String을 입력 값으로 받고, String 내의 숫자들을 더하는
add()메서드를 작성한다. add()메서드는 다음과 같은 테스트를 통과해야 한다.- 빈 문자열이 들어오면 0을 반환한다.
- 쉼표, 콜론, 커스텀 구분자로 구분된 숫자들을 더한다.
- 음수가 들어오면 예외 처리를 한다.
- 1000 이상의 숫자는 무시하고 계산한다.
- 각 조건별로 로직을 작성하고, 다음 조건에 맞게 조금씩 수정한다.
- 다음 조건 테스트를 진행하고 이전 테스트도 통과하는지 확인한다.
package com.example.test.calc;
import java.util.ArrayList;
import java.util.List;
public class StringCalculator {
public int add(String input) {
// ... 로직 작성
}
}
테스트 진행
테스트 클래스 생성
- 생성한
StringCalculator에서 우클릭 - Generate - Test를 선택해서StringCalculatorTest클래스를 생성한다.
StringCalculatorTest클래스에StringCalculator인스턴스를 생성하고,예상 결과와 메서드 실행 결과가 일치하는지 확인하는isRightResult를 작성했다.- 나중에 다시 확인해보니
import static org.assertj.core.api.Assertions.*;를 제거해서assert()메서드를 사용하지 못한 거였다. - 테스트에는 이 메서드를 사용하는 것이 좋다.
- 나중에 다시 확인해보니
setUp메서드를 통해 객체를 먼저 초기화한다.
package com.example.test.calc;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class StringCalculatorTest {
private StringCalculator calculator;
private boolean isRightResult(int result, int expected) {
return result == expected;
}
@BeforeEach
void setUp() {
calculator = new StringCalculator();
}
}
1. 빈 문자 처리
- 먼저 빈 문자가 들어오면 0을 반환하도록 처리하는 메서드를 작성한다.
package com.example.test.calc;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class StringCalculatorTest {
private StringCalculator calculator;
private boolean isRightResult(int result, int expected) {
return result == expected;
}
@BeforeEach
void setUp() {
calculator = new StringCalculator();
}
@Test
@DisplayName("빈 문자열 입력 시 0을 반환")
void emptyStringReturnsZero() {
System.out.println(calculator.add(""));
}
}
- Null값 비교와
String.isEmpty()메서드로 빈 문자열을 처리한다.
public class StringCalculator {
public int add(String input) {
if (input == null || input.isEmpty())
return 0;
}
}
2. 쉼표, 콜론, 커스텀 구분자 처리
- 쉼표, 콜론 구분자 처리
@Test
@DisplayName("쉼표 구분자로 숫자를 더한다")
void addNumbersWithComma() {
String input = "1,2,3";
int result = calculator.add(input);
System.out.println(isRightResult(result, 6));
String input2 = "1, 2, 3";
int result2 = calculator.add(input2);
System.out.println(isRightResult(result2, 6));
}
@Test
@DisplayName("콜론 구분자로 숫자를 더한다")
void addNumbersWithColon() {
String input = "1:2:3";
int result = calculator.add(input);
System.out.println(isRightResult(result, 6));
}
@Test
@DisplayName("쉼표와 콜론을 혼용할 수 있다")
void addNumbersWithMixedDelimiters() {
String input = "1,2:3";
int result = calculator.add(input);
System.out.println(isRightResult(result, 6));
}
- Spring을 구분자로 분리하는
split()을 사용하여,또는:을 기준으로 input을 분리한 뒤,Interger.parseInt()로 String을 int로 변환한 후 전체 합을 반환한다.
public class StringCalculator {
public int add(String input) {
int result = 0;
String[] splitedInput = input.split(",|:");
for (String str : splitedInput) {
if (str.isEmpty()) continue;
str = str.trim();
int num = Integer.parseInt(str);
result += num;
}
return result;
}
}
- 커스텀 구분자
@Test
@DisplayName("커스텀 구분자를 지정할 수 있다")
void customDelimiter() {
String input = "//;\\n1;2;3";
int result = calculator.add(input);
System.out.println(isRightResult(result, 6));
}
@Test
@DisplayName("커스텀 구분자가 여러 글자일 수 있다")
void multiCharacterCustomDelimiter() {
String input = "//[***]\\n1***2***3";
int result = calculator.add(input);
System.out.println(isRightResult(result, 6));
}
- 조건에 커스텀 구분자를 일단 문자로 생각해서 정규 표현식 중 숫자 제외한 모든 문자를 가리키는
\D를 사용해서 input을 분리했다.
public class StringCalculator {
public int add(String input) {
int result = 0;
// 숫자 제외 regex
String[] splitedInput = input.split("\\D");
for (String str : splitedInput) {
if (str.isEmpty()) continue;
str = str.trim();
int num = Integer.parseInt(str);
result += num;
}
return result;
}
}
3. 음수 처리
@Test
@DisplayName("음수 입력 시 예외가 발생한다")
void negativeNumberThrowsException() {
System.out.println(calculator.add("4:-1:3"));
}
@Test
@DisplayName("음수가 여러 개일 경우 모두 표시한다")
void multipleNegativeNumbersInExceptionMessage() {
System.out.println(calculator.add("-1:-2:1"));
}
- 2번에서
\D로 구분자를 설정하면 음수 표시로 사용하는-도 구분자로 인식되어 음수가 들어오지 못한다. - 그래서 숫자 또는
-를 제외한 문자 패턴 정규 표현식[^\\d-]+를 사용하여 숫자와 음수만 남기고 나머지를 모두 구분자 처리했다. - 또한 음수가 여러 개 있을 때 모든 음수를 출력하기 위해서 음수인 경우를 저장할
List를 추가하여 음수를List에 저장하고, 해당 리스트에 값이 있을 땐 커스텀 예외를 던졌다.
public class StringCalculator {
public int add(String input) {
int result = 0;
List<String> negatives = new ArrayList<>();
String[] splitedInput = input.split("[^\\d-]+");
for (String str : splitedInput) {
if (str.isEmpty()) continue;
str = str.trim();
int num = Integer.parseInt(str);
if (num < 0) {
negatives.add(str);
continue;
}
result += num;
}
if (!negatives.isEmpty()) {
assertThatThronwBy(negatives.toString());
}
return result;
}
class NegativeIntegerException extends ArithmeticException {
public NegativeIntegerException(String message) {
super("음수는 입력할 수 없습니다. \n 음수 목록 : " + message);
}
}
private void assertThatThronwBy(String target) {
throw new NegativeIntegerException(target);
}
}
4. 1000 이상 숫자 처리
@Test
@DisplayName("1000을 초과하는 숫자는 무시한다")
void ignoreNumbersGreaterThan1000() {
System.out.println(calculator.add("2,1001,6"));
}
- 더하는 동작에 1000과 숫자 비교를 넣어 1000 초과 숫자를 제외했다.
public class StringCalculator {
public int add(String input) {
int result = 0;
List<String> negatives = new ArrayList<>();
String[] splitedInput = input.split("[^\\d-]+");
for (String str : splitedInput) {
if (str.isEmpty()) continue;
str = str.trim();
int num = Integer.parseInt(str);
if (num < 0) {
negatives.add(str);
continue;
}
result += (num < 1000) ? num : 0;
}
if (!negatives.isEmpty()) {
assertThatThronwBy(negatives.toString());
}
return result;
}
class NegativeIntegerException extends ArithmeticException {
public NegativeIntegerException(String message) {
super("음수는 입력할 수 없습니다. \n 음수 목록 : " + message);
}
}
private void assertThatThronwBy(String target) {
throw new NegativeIntegerException(target);
}
}
최종 코드
package com.example.test.calc;
import java.util.ArrayList;
import java.util.List;
public class StringCalculator {
public int add(String input) {
int result = 0;
List<String> negatives = new ArrayList<>();
String[] splitedInput = input.split("[^\\d-]+");
for (String str : splitedInput) {
if (str.isEmpty()) continue;
str = str.trim();
int num = Integer.parseInt(str);
if (num < 0) {
negatives.add(str);
continue;
}
result += (num < 1000) ? num : 0;
}
if (!negatives.isEmpty()) {
assertThatThronwBy(negatives.toString());
}
return result;
}
class NegativeIntegerException extends ArithmeticException {
public NegativeIntegerException(String message) {
super("음수는 입력할 수 없습니다. \n 음수 목록 : " + message);
}
}
private void assertThatThronwBy(String target) {
throw new NegativeIntegerException(target);
}
}
package com.example.test.calc;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class StringCalculatorTest {
private StringCalculator calculator;
@BeforeEach
void setUp() {
calculator = new StringCalculator();
}
@Test
@DisplayName("빈 문자열 입력 시 0을 반환")
void emptyStringReturnsZero() {
System.out.println(calculator.add(""));
}
@Test
@DisplayName("쉼표 구분자로 숫자를 더한다")
void addNumbersWithComma() {
System.out.println(calculator.add("1,2,3"));
System.out.println(calculator.add("1, 2, 3"));
}
@Test
@DisplayName("콜론 구분자로 숫자를 더한다")
void addNumbersWithColon() {
System.out.println(calculator.add("1:2:3"));
}
@Test
@DisplayName("쉼표와 콜론을 혼용할 수 있다")
void addNumbersWithMixedDelimiters() {
System.out.println(calculator.add("1,2:3"));
}
@Test
@DisplayName("커스텀 구분자를 지정할 수 있다")
void customDelimiter() {
System.out.println(calculator.add("//;\\n1;2;3"));
}
@Test
@DisplayName("커스텀 구분자가 여러 글자일 수 있다")
void multiCharacterCustomDelimiter() {
System.out.println(calculator.add("//[***]\\n1***2***3"));
}
@Test
@DisplayName("음수 입력 시 예외가 발생한다")
void negativeNumberThrowsException() {
System.out.println(calculator.add("4:-1:3"));
}
@Test
@DisplayName("음수가 여러 개일 경우 모두 표시한다")
void multipleNegativeNumbersInExceptionMessage() {
System.out.println(calculator.add("-1:-2:1"));
}
@Test
@DisplayName("1000을 초과하는 숫자는 무시한다")
void ignoreNumbersGreaterThan1000() {
System.out.println(calculator.add("2,1001,6"));
}
}